package kevin.framework.basic.common.tree;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;

import kevin.framework.basic.common.ui.ClientButton;

/**
 * @ClassName: ListToTree
 * @Description: 将任意类型的列表数据转为树形数据，IListToTree<T>接口避免反射invoke，提高性能
 * 
 * @author kevin.huang
 * @date 2014-9-26 上午9:36:37
 * @param <T>
 */
public class ListToTree<T> {

	protected static String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
	// public Class<T> clazz= null;
	public List<ClientButton> btnList;

	public List<ClientButton> getBtnList() {
		return btnList;
	}

	public void setBtnList(List<ClientButton> btnList) {
		this.btnList = btnList;
	}

	private IListToTree<T> treeBean;

	public ListToTree(IListToTree<T> node) {
		// this.clazz=claz;
		btnList = new ArrayList<ClientButton>();
		treeBean = node;
	}

	public ListToTree(List<ClientButton> buttonlist, IListToTree<T> node) {
		// this.clazz=claz;
		btnList = buttonlist;
		treeBean = node;
	}


	/**
	 * @Title: getJSONArray @Description:
	 * 传入一个树形列表数据，和pid，会以pid为根转为树形JSONArray @param pid 必须传，不然不知道那个是根！ @param source
	 * 树形数据列表 @return @throws Throwable @throws
	 */
	public JSONArray getJSONArray(String pid, List<T> source) throws Throwable {
		return getTreeJsonArray(pid, source, false, null);
	}

	public JSONArray getJSONArray(String pid, List<T> source, boolean needTools) throws Throwable {
		return getTreeJsonArray(pid, source, needTools, null);
	}

	public JSONArray getJSONArray(String pid, List<T> source, Object extParams) throws Throwable {
		return getTreeJsonArray(pid, source, false, extParams);
	}

	public JSONArray getJSONArray(String pid, List<T> source, boolean needTools, Object extParams) throws Throwable {
		return getTreeJsonArray(pid, source, needTools, extParams);
	}

	/**
	 * @Title: getTreeJson @Description: 传入一个树形列表数据，和pid，会以pid为根转为树形json @param pid
	 * 必须传，不然不知道那个是根！ @param source 树形数据列表 @return @throws Throwable @throws
	 */
	public String getTreeJson(String pid, List<T> source) throws Throwable {
		return getTreeJson(pid, source, true);
	}

	/**
	 * @Title: getTreeJson @Description: 传入一个树形列表数据，和pid，会以pid为根转为树形json @param pid
	 * 必须传，不然不知道那个是根！ @param source 树形数据列表 @param needTools
	 * 树json是否需要工具栏 @return @throws Throwable @throws
	 */
	public String getTreeJson(String pid, List<T> source, boolean needTools) throws Throwable {
		return getTreeJson(pid, source, needTools, 0);
	}

	/**
	 * @Title: getTreeJson @Description: 传入一个树形列表数据，和pid，会以pid为根转为树形json @param pid
	 * 必须传，不然不知道那个是根！ @param source 树形数据列表 @param extParams
	 * 判断是否为子叶的扩展参数 @return @throws Throwable @throws
	 */
	public String getTreeJson(String pid, List<T> source, Object extParams) throws Throwable {

		return getTreeJson(pid, source, false, extParams);
	}

	/**
	 * @Title: getTreeJson @Description: 传入一个树形列表数据，和pid，会以pid为根转为树形json @param pid
	 * 必须传，不然不知道那个是根！ @param source 树形数据列表 @param needTools 树json是否需要工具栏 @param
	 * extParams 判断是否为子叶的扩展参数 @return @throws Throwable @throws
	 */
	public String getTreeJson(String pid, List<T> source, boolean needTools, Object extParams) throws Throwable {
		JSONArray jarray = getTreeJsonArray(pid, source, needTools, extParams);
		SerializeConfig ser = new SerializeConfig();
		ser.put(Date.class, new SimpleDateFormatSerializer(dateTimeFormat));
		return JSONObject.toJSONString(jarray, ser, SerializerFeature.DisableCircularReferenceDetect);
	}

	public JSONArray getTreeJsonArray(String pid, List<T> source, boolean needTools, Object extParams)
			throws Throwable {
		int deep = 0;
		List<TreeNode<T>> list = getTreeList(pid, source, extParams, deep + 1);
		JSONArray jarray = new JSONArray();
		for (TreeNode<T> node : list) {
			if (needTools && btnList.size() > 0) {
				jarray.add(node.toJSON(btnList, extParams));
			}else {
				jarray.add(node.toJSON(extParams));
			}				
		}
		SerializeConfig ser = new SerializeConfig();
		ser.put(Date.class, new SimpleDateFormatSerializer(dateTimeFormat));
		return jarray;
	}

	/**
	 * @Title: getTreeList @Description: 获取树形list @param pid pid @param source
	 * 数据源 @return @throws Throwable @throws
	 */
	public List<TreeNode<T>> getTreeList(String pid, List<T> source) throws Throwable {
		return getTreeList(pid, source, 0, 0);
	}

	/**
	 * @Title: getTreeList @Description: 获取树形list @param pid pid @param source
	 * 数据源 @param extParams 扩展参数 @return @throws Throwable @throws
	 */
	public List<TreeNode<T>> getTreeList(String pid, List<T> source, Object extParams, int deep) throws Throwable {
		List<TreeNode<T>> list = new ArrayList<TreeNode<T>>();
		/*
		 * if(clazz==null) throw new Exception("请先赋值clazz");
		 */
		TreeChildResut<T> reslist = getChildren(pid, source, extParams);
		for (T obj : reslist.resultList) {
			TreeNode<T> node = new TreeNode<T>();
			node.toTree = treeBean;
			node.data = obj;
			node.deep = deep;
			node.id = treeBean.getTreeId(obj, extParams);
			node.text = treeBean.getTreeText(obj, extParams);
			String tmp = treeBean.getTreePid(obj, extParams);
			node.pid = tmp == null || "null".equals(tmp) ? "" : tmp;
			if (hasChildren(node.id, reslist.nextSource, extParams)) {
				TreeChildResut<T> result = getChildren(node.id, reslist.nextSource, extParams);
				node.children = loopChildren(result, extParams, deep + 1);
			} else if (!treeBean.isTreeLeaf(obj, extParams)) {// 如果是空的父节点
				node.children = new ArrayList<TreeNode<T>>();
			}
			list.add(node);
		}

		return list;
	}

	/**
	 * @Title: hasChildren @Description: 判断是否存在子节点 @param pid @param
	 * source @return @throws Throwable @throws
	 */
	private boolean hasChildren(String pid, List<T> source, Object extParams) throws Throwable {
		boolean has = false;
		for (T obj : source) {
			String _pid = treeBean.getTreePid(obj, extParams);
			_pid = _pid == null || "null".equals(_pid) ? "" : _pid;
			if (_pid.equals(pid)) {
				has = true;
				break;
			}
		}
		return has;
	}

	// 如果是子元素并且其父元素在source 则不加入list
	private boolean canPutList(List<T> source, T bean, Object extParams) {
		boolean put = true;
		String pid = treeBean.getTreePid(bean, extParams);
		for (T obj : source) {
			String id = treeBean.getTreeId(obj, extParams);
			if (pid != null && pid.equals(id)) {
				put = false;
				break;
			}
		}
		return put;
	}

	private TreeChildResut<T> getChildren(String pid, List<T> source, Object extParams) throws Throwable {
		List<T> list = new ArrayList<T>();
		List<T> nextSource = new ArrayList<T>();
		TreeChildResut<T> result = new TreeChildResut<T>();
		result.resultList = list;
		result.nextSource = nextSource;
		for (T obj : source) {
			/*
			 * if(pid==null|| pid.equals("")){ //如果obj是子元素并且其父元素在source 则不加入list
			 * if(canPutList(source,obj,extParams)) list.add(obj); }else{
			 */
			String _pid = treeBean.getTreePid(obj, extParams);
			_pid = _pid == null || "null".equals(_pid) ? "" : _pid;
			if (pid.equals(_pid)) {
				list.add(obj);
			} else {
				nextSource.add(obj);
			}
			/* } */
		}
		// 剔除子元素
		return result;
	}

	private List<TreeNode<T>> loopChildren(TreeChildResut<T> result, Object extParams, int deep) throws Throwable {
		List<TreeNode<T>> list = new ArrayList<TreeNode<T>>();
		for (T obj : result.resultList) {
			TreeNode<T> node = new TreeNode<T>();
			node.toTree = treeBean;
			node.data = obj;
			node.deep = deep;
			node.id = treeBean.getTreeId(obj, extParams);
			node.text = treeBean.getTreeText(obj, extParams);
			String tmp = treeBean.getTreePid(obj, extParams);
			node.pid = tmp == null || "null".equals(tmp) ? "" : tmp;
			if (hasChildren(node.id, result.nextSource, extParams)) {
				TreeChildResut<T> result1 = getChildren(node.id, result.nextSource, extParams);
				node.children = loopChildren(result1, extParams, deep + 1);
			} else if (!treeBean.isTreeLeaf(obj, extParams)) {// 如果是空的父节点
				node.children = new ArrayList<TreeNode<T>>();
			}
			list.add(node);
		}
		return list;
	}
}
